package james.gan.bean;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

import james.gan.context.anno.AutoWired;
import james.gan.core.AutowireBeanFactory;
import james.gan.core.BeanDefinition;
import james.gan.core.BeanFacoty;
import james.gan.core.Resource;
import james.gan.utils.StringUtils;

/**
 * @Description:��������ʵ��
 * @author James
 * @date 2017/12/26
 */
public class DefaultListableBeanFactory implements BeanFacoty, Resource, AutowireBeanFactory {

  private final Resource resource;
  private final AutowireBeanFactory autowire;

  private final Map<String, BeanDefinition> beanCache =
      new ConcurrentHashMap<String, BeanDefinition>(256);

  private final AtomicBoolean init = new AtomicBoolean(false);

  public DefaultListableBeanFactory(Resource resource, AutowireBeanFactory autowire) {
    super();
    this.resource = resource;
    this.autowire = autowire;
    refresh();
  }

  private void refresh() {
    if (!init.get()) {
      beanCache.clear();
      beanCache.putAll(loadResources());
      init.set(true);
    }
  }

  public Object getBean(String name) {
    Object beanInstace = beanCache.get(name).getBeanInstace();
    try {
      autowire(beanInstace);
    } catch (IllegalArgumentException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return beanInstace;
  }

  public <T> T getBean(Class<T> requiredType) {
    return null;
  }

  public boolean containsBean(String name) {
    return false;
  }

  public void autowireBean(Object existingBean) {
    autowire.autowireBean(existingBean);
  }

  public Map<String, BeanDefinition> loadResources() {
    return resource.loadResources();
  }

  public void autowire(Object Bean) throws IllegalArgumentException, IllegalAccessException {
    Class<? extends Object> clzz = Bean.getClass();
    Field[] declaredFields = clzz.getDeclaredFields();
    for (Field f : declaredFields) {
      AutoWired annotation = f.getAnnotation(AutoWired.class);
      String value;
      if (annotation != null && StringUtils.NotBlank(value = annotation.value())
          && new DefaultBeanDefinition(clzz).matchClass(annotation.classType())) {
        Object obj = getBean(value);
        f.setAccessible(true);
        f.set(Bean, obj);
      }
    }
  }
}
